home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
macros
/
latex209
/
contrib
/
textyl
/
src
/
textyl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-07
|
80KB
|
3,423 lines
/* Output from p2c, the Pascal-to-C translator */
/* From input file "textyl.p" */
#include "defs.h"
#include "globals.h"
#include "tables.h"
extern int abs PP((int));
/*----------------------------------------------------------
TeXtyl line-drawing interface for TeX.
copyright (c) 1987 John S. Renner
All rights reserved.
ABSTRACT: TeXtyl reads in a DVI file, and processes 'specials'
that refer to graphics capabilities that it knows about,
like line, spline, ThickThinSpline, and musical
beams and slurs. TeXtyl then outputs a new DVI file,
with the special-macros expanded and converted to
DVI-commands for character setting.
DEPENDENCIES: Few assumptions about Pascal are assumed. All
identifiers are unique to eight characters. There are
notes to indicate system-dependencies.
I assume the standard definition of "READ(fil, x)" to be
equivalent to "x := fil^; GET(fil)" , and
"WRITE(fil, x)" == "fil^ := x; PUT(fil)" .
Arrays are passed by reference (VAR) for efficiency.
See also the "sysdependent" procedure;
Problem areas, or areas for expansion are marked with ###
-------------------------------------------------------------*/
/*-Revision History:
Jun. 1986 v1.0 Basic version of TeXtyl
Dec. 1986 v1.1 Added adaptive subdivision for spline
interpolation. Added Cardinal basis.
Mar. 1987 v1.2 Added F and W flags for beginfigure
to allow required and/or actual dimensions
to interface with files output by the
DP drawing program from Carnegie-Mellon
also various fixes
Apr. 1987 v1.3 Added linestyles (dotted, dashed, dotdashed)
Aug. 1991 Translated to C with p2c, then hacked a bit. (Ken Yap)
*/
/* ===========================TYPES============================= */
/* ---- PUBLIC types ---- */
typedef int MusIndex;
typedef int SplineSegments[MAXSPLINESEGS][2];
/* ----- Private Types ---- */
typedef struct FontInfRec
{
int32 Cht, Cdp, Cwd;
double Angle;
} FontInfRec;
/* vector font info */
typedef struct VectFontInfRec
{
VectKind vkind;
int32 DesSize, PenSize;
VThickness psize;
int32 MaxVectLen;
charstring FontName;
int32 Cksum;
int Isdefined;
int32 DVIFontNum;
FontInfRec FontInfo[128];
} VectFontInfRec;
/* music font info */
typedef struct MusFontInfRec
{
int32 DesSize, Family;
charstring FontName;
int32 Cksum;
int Isdefined;
int32 DVIFontNum, Staffsize, ghu, gvu;
FontInfRec FontInfo[128];
} MusFontInfRec;
/*
* representation of list of fonts that have to be defined
* before we output the BOP of the page we just scanned
*/
typedef struct ToBeDefinedRec
{
char which;
int32 indx;
} ToBeDefinedRec;
/* ==============================VARS============================ */
/* ----- Private vars */
static int32 ourxpos; /* internal x-position on page */
static int32 ourypos; /* internal y-position on page */
static VectFontInfRec *VFontTable[SizVFontTable];
static MusFontInfRec *MFontTable[SizMFontTable];
/* the font tables, and the number of fonts defined in each */
static int32 VFontsDefd, MFontsDefd, LFontsDefd;
static int GDVIFN = 301; /* dvi font number currently in use */
/* table of fonts yet To-Be-Defined */
static ToBeDefinedRec TBD[MAXTBDs];
static int32 FTBDs; /* number of fonts to be defined for current page */
static Item *pageitems;
/*
* list of primitives in current use in the current figure on the current page
*/
static int32 specstart = 0;
/*
* the place in the DVI buffer where the start of the special begins.
* this is so that we know how far to back up and over-write
* the old \special macro string with the cmds of our 'macro-expansion'
*/
static int32 multifigure; /* depth of definition recursion of figures */
static int skiptsclamp; /* DEBUG: should we skip post-clamping ties */
static int ErrorOccurred; /* global flag in case some error happened */
/* ----- End private vars */
static short tfm[TFMSIZE + 101];
static char s = 0;
struct stackrec
{
int32 sh, sv, sw, sx, sy, sz;
} stack[STACKSIZE + 1];
static int32 inwidth[256];
static int32 tfmchecksum;
static double conv, trueconv;
static int32 numerator, denominator;
static double mag, magfactor;
static int32 maxv, maxh, maxs, maxpages = 10000, totalpages;
static double resolution = 300.0;
static int inpostamble;
static int32 newbackptr = -1, oldbackptr = -1, p, k;
/* forward declarations */
static void definebeams PP((MusFontInfRec ** M));
static void definevectors PP((VectFontInfRec ** Vec));
static jmp_buf _JL666;
static int
opentfmfile(tfmname)
charstring tfmname;
{
charstring thefilename;
char *path, *p, *q, *getenv PP((char *));
if ((path = getenv("TEXFONTS")) == 0)
path = DEFTEXFONTS;
if (tfmfile != NULL)
{
fclose(tfmfile);
tfmfile = NULL;
}
for (p = path; p != 0 && tfmfile == NULL; p = q ? q + 1 : 0)
{
if ((q = strchr(p, ':')) == 0)
strcpy(thefilename, p);
else
strncpy(thefilename, p, q - p);
strcat(thefilename, "/");
if (strcmp(thefilename, "./") == 0)
thefilename[0] = '\0';
strcat(thefilename, tfmname);
tfmfile = fopen(thefilename, "r");
}
return (tfmfile != NULL);
}
void
jumpout()
{
longjmp(_JL666, 1); /* global label */
}
void
complain(severity)
int severity;
{
fprintf(logfile, "Error in fig#%ld on page %ld\n", pgfigurenum, currpagenum);
switch (severity)
{
case ERRNOTBAD:
putc(ERRSIGNAL, logfile);
break;
case ERRBAD:
putc(ERRSIGNAL, logfile);
ErrorOccurred = true;
break;
case ERRREALBAD:
fprintf(logfile, "%c! ", ERRSIGNAL);
ErrorOccurred = true;
break;
}
}
double
float_(i)
int32 i;
{
return ((double) i);
}
static int
tolowercase(let)
int let;
{
return (isupper(let) ? tolower(let) : let);
}
#define streq(a,b,n) (!strncmp((a),(b),(n)))
/*
* Move the current DVI position to posx, posy by moving relatively from our current position and store the new position
*/
void
isetpos(posx, posy)
int posx, posy;
{
ScaledPts dy, dx;
int32 numbytes;
dx = posx - ourxpos;
dy = posy - ourypos;
numbytes = 1;
if (dx < 128 && dx >= -128)
numbytes = 1;
else if (dx < 32768 && dx >= -32768)
numbytes = 2;
else if (dx < TWO23 && dx >= -TWO23)
numbytes = 3;
else if (dx < TWO31 && dx >= -TWO31)
numbytes = 4;
else
{
complain(ERRREALBAD);
fprintf(logfile, "Panic: dx is too big/small in isetpos: %12ld\n", dx);
}
cmd1byte(RIGHTLEFT + numbytes - 1);
/* number of bytes in its arg list */
cmdSigned(dx, numbytes);
numbytes = 1;
if (dy < 128 && dy >= -128)
numbytes = 1;
else if (dy < 32768 && dy >= -32768)
numbytes = 2;
else if (dy < TWO23 && dy >= -TWO23)
numbytes = 3;
else if (dy < TWO31 && dy >= -TWO31)
numbytes = 4;
else
{
complain(ERRREALBAD);
fprintf(logfile, "Panic: dy is too big/small in isetpos: %12ld\n", dy);
}
cmd1byte(DOWNUP + numbytes - 1);
cmdSigned(dy, numbytes);
ourxpos = posx;
ourypos = posy;
}
/* put out a character */
static void
iputchar(charno)
int charno;
{
cmd1byte(PUT1);
cmd1byte(charno);
}
/*
* set the font number, but only if it is different than the last one
* we accessed.
*/
void
isetfont(DVINum)
int DVINum;
{
if (ourfontnum == DVINum)
return;
cmd1byte(USEFONT);
cmd2byte(DVINum);
ourfontnum = DVINum;
}
/* Assumes that the correct font is currently set */
static void
Tyldot(dotx, doty)
int32 dotx, doty;
{
if (dotx != 0 && doty != 0)
isetpos(dotx, doty);
iputchar(DOTCHAR);
}
/*
* ### Note: "pageitems" could be extended to be a list
* { of macrodefinitions which contain primitives , and { then could be
* instanced. E.g., a library of common { figures callable from \special level
*/
void
pushItem(depth, newthing)
int depth;
Item *newthing;
{
Item *i, *p;
if (pageitems == NULL)
{
if (newthing->kind == Afigure)
{
pageitems = newthing;
return;
}
pageitems = NewItem(Afigure);
pageitems->UU.U8.depthnumber = depth;
}
/* Assume that pageitems points to Afigure */
/* traverse the list */
i = pageitems; /* point to front of list for now */
p = i->UU.U8.body->things;
while (p != NULL)
{
if (depth == i->UU.U8.depthnumber)
{ /* simple push */
/*
* Note: this is the case when pushing another figure item onto
* an already-existing list. We push the
* newfigure with a depth of (fig^.depthnumber - 1) because
* it really is part of the higer-level figure
*/
break;
}
if (depth <= i->UU.U8.depthnumber)
continue;
/* there MUST be a figure with a higher number deeper */
while (p->kind != Afigure && p->nextitem != NULL)
p = p->nextitem;
if (p->kind == Afigure)
{
i = p;
p = i->UU.U8.body->things;
}
else
{
complain(ERRREALBAD);
fprintf(logfile,
"OOPS p^.kind isnt a figure. It must be near endoflist\n");
}
}
/*
* we have the correct front of list-list, and i points to Afigure item
*/
newthing->nextitem = p;
i->UU.U8.body->things = newthing;
}
static double
Tgetfixword(k)
int k;
{
short a;
int32 f;
a = tfm[k + 100] * 16 + tfm[k + 101] / 16;
f = ((tfm[k + 101] & 15) * 256 + tfm[k + 102]) * 256 + tfm[k + 103];
if (a <= 2047)
return (a + (double) f / TWO20);
a = 4096 - a;
if (f > 0)
{
f = TWO20 - f;
a--;
}
return (a + (double) f / TWO20);
}
static int32
TgetSigned(k)
int k;
{
int32 i;
i = tfm[k + 100];
if (i < 128)
i -= 256;
return (((i * 256 + tfm[k + 101]) * 256 + tfm[k + 102]) * 256 + tfm[k + 103]);
}
/*
* open a .tfm file and return the parameters in it.
* Used only in conjuction with the vector and music fonts
*/
static void
gettfm(tfmfilnam, dessize, p1, p2, p3, p4, p5, p6, p7, cksum)
charstring tfmfilnam;
int32 *dessize, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *cksum;
{
int32 tfmptr, lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, charbase, widthbase, heightbase, depthbase,
italicbase, ligkernbase, kernbase, extenbase, parambase;
ScaledPts tempdesignsize;
*p1 = 0;
*p2 = 0;
*p3 = 0;
*p4 = 0;
*p5 = 0;
*p6 = 0;
*p7 = 0;
*cksum = -1;
if (!opentfmfile(tfmfilnam))
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loaded, TFM file can't be opened!\n", tfmfilnam);
jumpout();
}
tfm[100] = Tgetc();
tfm[101] = Tgetc();
lf = tfm[100] * 256 + tfm[101];
if (lf * 4 - 1 > TFMSIZE)
{
complain(ERRREALBAD);
fprintf(logfile, "The tfm file:%s is bigger than I can handle!\n", tfmfilnam);
return;
}
for (tfmptr = 102; tfmptr <= lf * 4 + 99; tfmptr++)
tfm[tfmptr] = Tgetc();
tfmptr = 2;
lh = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
bc = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
ec = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
nw = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
nh = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
nd = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
ni = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
nl = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
nk = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
ne = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
np = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
tfmptr += 2;
if (lf != lh + ec - bc + nw + nh + nd + ni + nl + nk + ne + np + 7)
{
complain(ERRREALBAD);
fprintf(logfile, "%s: subfile sizes don't add up to the stated total!\n", tfmfilnam);
fprintf(logfile,
"Sorry, but I can't go on; are you sure this is a TFM?\n");
return;
}
if (bc > ec + 1 || ec > 255)
{
complain(ERRREALBAD);
fprintf(logfile, "The character code range %ld..%ld is illegal!\n", bc, ec);
fprintf(logfile, "Sorry, but I can't go on; are you sure this is a TFM?\n");
return;
}
charbase = lh - bc + 6;
widthbase = charbase + ec + 1;
heightbase = widthbase + nw;
depthbase = heightbase + nh;
italicbase = depthbase + nd;
ligkernbase = italicbase + ni;
kernbase = ligkernbase + nl;
extenbase = kernbase + nk;
parambase = extenbase + ne - 1;
*dessize = (int32) floor(Tgetfixword(28) * SPPERPT + 0.5);
/* now in ScaledPts */
tempdesignsize = (int32) floor(*dessize * magfactor + 0.5);
*cksum = TgetSigned(24);
/* return the special 7 parameters for the font */
*p1 = (int32) floor(Tgetfixword((parambase + 1) * 4) * tempdesignsize + 0.5);
*p2 = (int32) floor(Tgetfixword((parambase + 2) * 4) * tempdesignsize + 0.5);
*p3 = (int32) floor(Tgetfixword((parambase + 3) * 4) * tempdesignsize + 0.5);
*p4 = (int32) floor(Tgetfixword((parambase + 4) * 4) * tempdesignsize + 0.5);
*p5 = (int32) floor(Tgetfixword((parambase + 5) * 4) * tempdesignsize + 0.5);
*p6 = (int32) floor(Tgetfixword((parambase + 6) * 4) * tempdesignsize + 0.5);
*p7 = (int32) floor(Tgetfixword((parambase + 7) * 4) * tempdesignsize + 0.5);
}
static void
initVnMnLtables()
{
int32 i;
for (i = 0; i < SizVFontTable; i++)
VFontTable[i] = NULL;
for (i = 0; i < SizMFontTable; i++)
MFontTable[i] = NULL;
for (i = 0; i < SizLFontTable; i++)
LFontTable[i] = NULL;
VFontsDefd = 0;
MFontsDefd = 0;
LFontsDefd = 0;
}
static void
fonttobedefined(kind, findex)
char kind;
int findex;
{
FTBDs++;
/*
* reset this to zero after outputting 1. fontdefs 2. bop
* 3. contents of dvi page 4. eop
*/
TBD[FTBDs - 1].which = kind;
TBD[FTBDs - 1].indx = findex;
}
static void
enterfont(fontnum, ck, scalefact, dessiz, nam)
int32 fontnum, ck, scalefact, dessiz;
charstring nam;
{
int32 n, len;
cmd1byte(FONTDEF);
cmd2byte(fontnum);
cmd4byte(ck);
cmd4byte(scalefact);
cmd4byte(dessiz);
cmd1byte(USESTDAREA);
cmd1byte(len = strlen(nam) - 4);/* skip the length of the .tfm suffix */
for (n = 0; n < len; n++) /* skip the .tfm suffix */
cmd1byte(nam[n]);
}
static void
Outputfont(fontnum, ck, scalefact, dessiz, nam)
int32 fontnum, ck, scalefact, dessiz;
charstring nam;
{
int32 n, len;
OutputByte(FONTDEF);
Output2Byte(fontnum);
Output4Byte(ck);
Output4Byte(scalefact);
Output4Byte(dessiz);
OutputByte(USESTDAREA);
/* dont output the default dir prefix, nor the .tfm suffix */
OutputByte(len = strlen(nam) - 4);
for (n = 0; n < len; n++)
OutputByte(nam[n]);
}
void
defineNewfonts()
{
/*
* this needs to be done before first access to a font
* on a page later someone else will have to re-define all of them
* in the postamble
*/
int32 i, f, FORLIM;
VectFontInfRec *WITH;
MusFontInfRec *WITH1;
LabFontInfRec *WITH2;
FORLIM = FTBDs;
for (i = 0; i < FORLIM; i++)
{
if (TBD[i].which == 'V')
{
f = TBD[i].indx;
WITH = VFontTable[f - 1]; /* with */
if (WITH->Isdefined)
continue;
Outputfont(WITH->DVIFontNum, WITH->Cksum, WITH->DesSize, WITH->DesSize,
WITH->FontName);
WITH->Isdefined = true;
} /* if */
else if (TBD[i].which == 'M')
{
f = TBD[i].indx;
WITH1 = MFontTable[f - 1]; /* with */
if (WITH1->Isdefined)
continue;
Outputfont(WITH1->DVIFontNum, WITH1->Cksum, WITH1->DesSize,
WITH1->DesSize, WITH1->FontName);
WITH1->Isdefined = true;
}
else if (TBD[i].which == 'L')
{
f = TBD[i].indx;
WITH2 = LFontTable[f - 1]; /* with */
if (WITH2->Isdefined) /* ### is this right? */
continue;
Outputfont(WITH2->DVIFontNum, WITH2->Cksum, WITH2->DesSize,
WITH2->DesSize, WITH2->FontName);
WITH2->Isdefined = true;
}
else
{
complain(ERRREALBAD);
fprintf(logfile, "Unknown type of font to be defined:\"%c\"\n",
TBD[i].which);
}
}
}
static int32
GetMusFont(stfsiz, fam)
int32 stfsiz, fam;
{
charstring mustfmnam;
MusIndex i;
ScaledPts design, p1, p2, p3, p4, linesp, gwidth, p7;
int32 cksm, FORLIM;
MusFontInfRec *WITH;
/* see if it already exists */
FORLIM = MFontsDefd;
for (i = 1; i <= FORLIM; i++)
{ /* loop through since there are few */
WITH = MFontTable[i - 1];
if (WITH->Staffsize == stfsiz && WITH->Family == fam)
return (i);
}
sprintf(mustfmnam, "mus%c%c.tfm", stfsiz + '0', fam + '0');
gettfm(mustfmnam, &design, &p1, &p2, &p3, &p4, &linesp, &gwidth, &p7, &cksm);
MFontsDefd++;
if (MFontsDefd > SizMFontTable)
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loadable. Size of Music Font table too small\n", mustfmnam);
jumpout();
}
i = MFontsDefd;
MFontTable[i - 1] = (MusFontInfRec *) xmalloc(sizeof(MusFontInfRec));
WITH = MFontTable[i - 1];
WITH->Staffsize = stfsiz;
WITH->Family = fam;
WITH->DesSize = design;
strcpy(WITH->FontName, mustfmnam);
WITH->Cksum = cksm;
WITH->ghu = (int32) floor(gwidth / QNOTEGHUS + 0.5);
WITH->gvu = (int32) floor(linesp / QNOTEGVUS + 0.5);
WITH->DVIFontNum = GDVIFN++;
WITH->Isdefined = false;
/* call someone to do the defns of cdp, cht, cwd foreach beam */
definebeams(&MFontTable[i - 1]);
fonttobedefined('M', i);
return (i);
}
int32
GetVectFont(size, vk)
VThickness size;
VectKind vk;
{
charstring vectfmnam;
VecIndex i;
ScaledPts design, p1, p2, w0, w1, maxveclen, p6, p7;
int32 cksm, r, FORLIM;
VectFontInfRec *WITH;
/* see if it already exists */
FORLIM = VFontsDefd;
for (i = 1; i <= FORLIM; i++)
{ /* with */
WITH = VFontTable[i - 1];
if (WITH->psize == size && WITH->vkind == vk)
return (i);
}
switch (vk)
{
case VKCirc:
r = 'c';
break;
case VKVert:
r = 'v';
break;
case VKHort:
r = 'h';
break;
}
sprintf(vectfmnam, "%cvec%d.tfm", r, size);
gettfm(vectfmnam, &design, &p1, &p2, &w0, &w1, &maxveclen, &p6, &p7, &cksm);
VFontsDefd++;
if (VFontsDefd > SizVFontTable)
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loadable. Size of Vector Font table too small\n", vectfmnam);
jumpout();
}
i = VFontsDefd;
VFontTable[i - 1] = (VectFontInfRec *) xmalloc(sizeof(VectFontInfRec));
WITH = VFontTable[i - 1];
WITH->vkind = vk;
WITH->psize = size;
WITH->DesSize = design;
if (vk == VKVert)
WITH->PenSize = w1;
else
WITH->PenSize = w0;
WITH->PenSize = (int32) floor(size * (MAXVECLENsp / 16.0) + 0.5);
WITH->MaxVectLen = maxveclen;
strcpy(WITH->FontName, vectfmnam);
WITH->Cksum = cksm;
WITH->Isdefined = false;
WITH->DVIFontNum = GDVIFN++;
definevectors(&VFontTable[i - 1]);
/* someone asked for it, so they must want it, and we should fntdef it */
fonttobedefined('V', i);
return (i);
}
/*----------------------------------------------------------*/
int32
GetLabFont(style)
int32 style;
{
charstring labtfmnam;
int32 i, cksm, FORLIM;
ScaledPts design, p1, space, p3, p4, p5, p6, p7;
LabFontInfRec *WITH;
if (style > MAXLABELFONTS)
style = 1;
FORLIM = LFontsDefd;
for (i = 1; i <= FORLIM; i++)
{
WITH = LFontTable[i - 1];
if (WITH->internalnumber == style)
return (i);
}
switch (style)
{
case 1: /* cmtt10 */
strcpy(labtfmnam, "cmtt10");
break;
case 2: /* cmb10 */
strcpy(labtfmnam, "cmb10");
break;
case 3: /* cmsl10 */
strcpy(labtfmnam, "cmsl10");
break;
case 4: /* cmtt8 */
strcpy(labtfmnam, "cmtt8");
break;
case 5: /* cmsl8 */
strcpy(labtfmnam, "cmsl8");
break;
}
strcat(labtfmnam, ".tfm");
gettfm(labtfmnam, &design, &p1, &space, &p3, &p4, &p5, &p6, &p7, &cksm);
LFontsDefd++;
if (LFontsDefd > SizLFontTable)
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loadable. Size of Label Font table too small\n", labtfmnam);
jumpout();
}
i = LFontsDefd;
LFontTable[i - 1] = (LabFontInfRec *) xmalloc(sizeof(LabFontInfRec));
WITH = LFontTable[i - 1]; /* with */
strcpy(WITH->FontName, labtfmnam);
WITH->Cksum = cksm;
WITH->DesSize = design;
WITH->internalnumber = style;
WITH->spacewidth = space;
WITH->DVIFontNum = GDVIFN++;
WITH->Isdefined = false;
fonttobedefined('L', i);
return (i);
}
static double
vectangle(dx, dy)
int32 dx, dy;
{
if (dx != 0)
return (atan(dy / (double) dx) * RADTODEG);
else
return (dy > 0 ? 90.0 : -90.0);
}
static void
definevectors(Vec)
VectFontInfRec **Vec;
{
/* var Vec: pVectFontInfRec */
int i;
double units;
VectFontInfRec *V;
FontInfRec *F;
struct vecinfo *v;
V = *Vec;
units = V->MaxVectLen / 16.0;
for (i = 0, F = V->FontInfo, v = vectab; i < 128; ++i, ++F, ++v)
{
F->Cht = floor(v->Cht * units + 0.5);
F->Cdp = floor(v->Cdp * units + 0.5);
F->Cwd = floor(v->Cwd * units + 0.5);
F->Angle = v->Angle;
}
}
/*
* If, for some reason, you do not want to deal with music capabilities,
* replace the body of this procedure with just a begin
* end; pair and also the TylBeam proc.
*/
static void
definebeams(M)
MusFontInfRec **M;
{
/* var M : pMusFontInfRec */
}
#define UnitRadius 16777216/* TWO24 scaledpts */
/*
* use pre-calculated coordinates of a circle that has a given unit-radius.
* Scale those points to fit the desired radius
*/
void
defineCircleCpts(rad, centx, centy, CircleCpt, numpts)
int32 rad, centx, centy;
int32 (*CircleCpt)[2];
int32 *numpts;
{
double ratio;
if (rad == 0)
{
complain(ERRBAD);
fprintf(logfile, "Error in fig#%ld on page %ld\n",
pgfigurenum, currpagenum);
fprintf(logfile, "Zero length radius for circle! Setting to 1 sp\n");
rad = 1;
}
ratio = float_(rad) / float_(UnitRadius);
*numpts = 16;
CircleCpt[1][0] = (int32) floor(ratio * 16777216.00000 + 0.5) + centx;
CircleCpt[1][1] = centy;/* round (ratio * 0.00000) */
CircleCpt[2][0] = (int32) floor(ratio * 15500126.47492 + 0.5) + centx;
CircleCpt[2][1] = (int32) floor(ratio * 6420362.60441 + 0.5) + centy;
CircleCpt[3][0] = (int32) floor(ratio * 11863283.20303 + 0.5) + centx;
CircleCpt[3][1] = (int32) floor(ratio * 11863283.20303 + 0.5) + centy;
CircleCpt[4][0] = (int32) floor(ratio * 6420362.60441 + 0.5) + centx;
CircleCpt[4][1] = (int32) floor(ratio * 15500126.47492 + 0.5) + centy;
CircleCpt[5][0] = centx;/* round (ratio * -0.00000) */
CircleCpt[5][1] = (int32) floor(ratio * 16777216.00000 + 0.5) + centy;
CircleCpt[6][0] = (int32) floor(0.5 - ratio * 6420362.60441) + centx;
CircleCpt[6][1] = (int32) floor(ratio * 15500126.47492 + 0.5) + centy;
CircleCpt[7][0] = (int32) floor(0.5 - ratio * 11863283.20303) + centx;
CircleCpt[7][1] = (int32) floor(ratio * 11863283.20303 + 0.5) + centy;
CircleCpt[8][0] = (int32) floor(0.5 - ratio * 15500126.47492) + centx;
CircleCpt[8][1] = (int32) floor(ratio * 6420362.60441 + 0.5) + centy;
CircleCpt[9][0] = (int32) floor(0.5 - ratio * 16777216.00000) + centx;
CircleCpt[9][1] = centy;/* round (ratio * -0.00000) */
CircleCpt[10][0] = (int32) floor(0.5 - ratio * 15500126.47492) + centx;
CircleCpt[10][1] = (int32) floor(0.5 - ratio * 6420362.60441) + centy;
CircleCpt[11][0] = (int32) floor(0.5 - ratio * 11863283.20303) + centx;
CircleCpt[11][1] = (int32) floor(0.5 - ratio * 11863283.20303) + centy;
CircleCpt[12][0] = (int32) floor(0.5 - ratio * 6420362.60441) + centx;
CircleCpt[12][1] = (int32) floor(0.5 - ratio * 15500126.47492) + centy;
CircleCpt[13][0] = centx; /* round (ratio * 0.00000) */
CircleCpt[13][1] = (int32) floor(0.5 - ratio * 16777216.00000) + centy;
CircleCpt[14][0] = (int32) floor(ratio * 6420362.60441 + 0.5) + centx;
CircleCpt[14][1] = (int32) floor(0.5 - ratio * 15500126.47492) + centy;
CircleCpt[15][0] = (int32) floor(ratio * 11863283.20303 + 0.5) + centx;
CircleCpt[15][1] = (int32) floor(0.5 - ratio * 11863283.20303) + centy;
CircleCpt[16][0] = (int32) floor(ratio * 15500126.47492 + 0.5) + centx;
CircleCpt[16][1] = (int32) floor(0.5 - ratio * 6420362.60441) + centy;
/* create the pre-list phantom */
CircleCpt[0][0] = CircleCpt[16][0];
CircleCpt[0][1] = CircleCpt[16][1];
}
#undef UnitRadius
/*
* compute control points for an arc going from startangle to stopangle, centered at (centx, centy)
*/
void
definearcpts(rad, centx, centy, startang, stopang, cpts, nknots)
int32 rad, centx, centy, startang, stopang;
int32 (*cpts)[2];
int32 *nknots;
{
int32 n;
double a, b, curr, delta;
int32 i;
a = startang * DEGTORAD;
b = stopang * DEGTORAD;
n = 16;
if (a > b)
a -= 2 * PI;
delta = fabs(b - a) / n;
if (a == b)
{
complain(ERRNOTBAD);
fprintf(logfile, "Error in compute arc points:: should be a circle\n");
}
curr = a;
i = 1;
while (curr <= b)
{ /* make arc about (centx,centy) */
cpts[i][0] = (int32) floor(rad * cos(curr) + 0.5) + centx;
cpts[i][1] = (int32) floor(rad * sin(curr) + 0.5) + centy;
i++;
curr += delta;
}
/*
* go one point beyond -- around the arc so that we can have
* good smoothness for this phantom point
*/
cpts[i][0] = (int32) floor(rad * cos(b + delta) + 0.5) + centx;
cpts[i][1] = (int32) floor(rad * sin(b + delta) + 0.5) + centy;
/* and one phantom point before the list */
cpts[0][0] = (int32) floor(rad * cos(a - delta) + 0.5) + centx;
cpts[0][1] = (int32) floor(rad * sin(a - delta) + 0.5) + centy;
*nknots = i - 1;
}
static int
isaletter(b)
int b;
{
return (isalpha(b) || b == '@' || b == '"');
}
static int
getnumber(cpp)
char **cpp;
{
int n;
int isneg;
n = 0;
isneg = false;
for ( ; **cpp != '\0' && (!isdigit(**cpp)); ++*cpp)
if (**cpp == '-')
isneg = true;
while (isspace(**cpp)) /* Skip spaces */
++*cpp;
for ( ; **cpp != '\0' && isdigit(**cpp); ++*cpp)
n = n * 10 + **cpp - '0';
return (isneg ? -n : n);
}
static int
getletter(cpp)
char **cpp;
{
char *cp;
cp = *cpp;
/* non letter */
for (cp = *cpp; *cp != '\0' && !isaletter(*cp) && !isspace(*cp); ++cp)
;
if (*cp != '\0' && (isaletter(*cp) ||
(isspace(*cp) && !isdigit(*cp))))
{
*cpp = cp + 1;
return (*cp);
}
return (' ');
}
static int
getanything(cpp)
char **cpp;
{
char c;
if ((c = **cpp) != '\0')
{
++*cpp;
return (c);
}
return (' ');
}
/*****************************************************
The following routines look for key - letter tokens
that indicate certain attributes for a primitive.
Currently, the letters used are:
Sfor scaled-points measurement
Pfor printers points
Mmillimeters measurement
Cuse a Circular vector for drawing
HHorizontal-pen vector
VVertical vector
BB-spline
IInterpolating B-spline
KCatmull-Rom spline
DCardinal spline
UOpen spline
Oclosed spline
Xput marks on spline control pts
TTransformation marker
RRegular beam characters
GGrace Beam characters
@Specify center-point for arc/circle
LLine-style
Ffor beginfigure: Fit figure to wid/ht
Wfor beginfigure: figure was created at this wid & ht
***************************************************/
static void
gettransforms(sc1, sc2, r, tr1, tr2, cpp)
double *sc1, *sc2, *r;
int32 *tr1, *tr2;
char **cpp;
{
char *cp;
*sc1 = 1.0;
*sc2 = 1.0;
*tr1 = 0;
*tr2 = 0;
*r = 0.0;
for (cp = *cpp; *cp != '\0'; ++cp)
{
if (*cp == 't' || *cp == 'T')
{
if (!isaletter(cp[-1]) && !isaletter(cp[1]))
{
/* get transform parameters and modify ptr */
*cpp = cp;
*sc1 = getnumber(cpp) / 100.0;
*sc2 = getnumber(cpp) / 100.0;
*tr1 = getnumber(cpp);
*tr2 = getnumber(cpp);
*r = float_(getnumber(cpp));
/* degrees about primitive center */
if (*r < 0.0)
*r += 360.0;
break;
}
}
}
}
static int
findmarker(set, cp)
char *set;
char *cp;
{
for ( ; *cp != '\0'; ++cp)
{
if (strchr(set, *cp))
if (!isaletter(cp[-1]) && !isaletter(cp[1]))
return (tolowercase(*cp));
}
return (0);
}
#define findscale(p) findmarker("sSpPmM", p)
#define findvectkind(p) findmarker("cChHvV", p)
#define findlinestyle(p) findmarker("lL", p)
#define findbeamkind(p) findmarker("rRgG", p)
#define findsplinekind(p) findmarker("bBiIkKdD", p)
#define findsplclosure(p) findmarker("oOuU", p)
#define findatsign(p) findmarker("@", p)
#define finddotmark(p) findmarker("xX", p)
#define findfigdimens(p) findmarker("wW", p)
#define findfitsizes(p) findmarker("fF", p)
static double
thescaleof(scal)
int32 scal;
{
if (scal == 's')
return (1 * magfactor);
if (scal == 'p')
return (SPPERPT * magfactor);
if (scal == 'm')
return (SPPERMM * magfactor);
if (scal == 0)
return (SPPERPT * magfactor);
}
static VectKind
thevectorof(vkin)
int32 vkin;
{
if (vkin == 'c')
return VKCirc;
if (vkin == 'v')
return VKVert;
if (vkin == 'h')
return VKHort;
if (vkin == 0)
return VKCirc;
}
static LineStyle
thestyleof(linest)
int32 linest;
{
static LineStyle styletab[4] = {solid, dotted, dashed, dotdash};
if (linest > 3 || linest < 0)
linest = 0;
return (styletab[linest]);
}
static void
tylspecials(cp)
char *cp;
{
/*
* specnum is the DVI-number of the special
* nbytes is the number of parameter bytes
*/
int32 siz, numknots; /* Lots of temp vars that we use */
int32 x1, y1, x2, y2;
double sx100, sy100, rot, SPscale;
ScaledPts transx, transy, minx, miny, maxx, maxy;
ControlPoints cpts;
VThickness thk;
LineStyle patt;
ThickAryType TTary;
VectKind vk;
BeamKind bk;
int32 markdiam, radius, ang1, ang2;
charstring phrase;
int32 style;
char nam[5]; /* the first parameter of the \special */
char let;
int32 i;
Item *pi;
int32 maxthk, minthk;
SplineKind splinetype;
int isclosedspline;
int free PP((char *));
/* Lets look for a primitive to tyl */
for ( ; !isaletter(*cp) && *cp != '\0'; ++cp)
;
/* get the name of the primitive */
for (i = 0; isaletter(*cp); ++cp)
if (i < 4)
nam[i++] = tolowercase(*cp);
nam[i] = '\0';
/* --- BEGINFIGURE ---- */
if (streq(nam, "beginfigure", 3))
{
multifigure++;
i = findscale(cp);
SPscale = thescaleof(i);
gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);
/*
* store all the primitives on pageitems, and dont output them
* until we get a endfigure. this way, we can take
* care of dealing with all the primitives according to some
* global tranformation for the whole figure
*/
pi = NewItem(Afigure);
pi->UU.U8.figtheta = rot;
pi->UU.U8.fsx = sx100;
pi->UU.U8.fsy = sy100;
pi->UU.U8.fdx = (int32) floor(transx * SPscale + 0.5);
pi->UU.U8.fdy = (int32) floor(transy * SPscale + 0.5);
pi->UU.U8.depthnumber = multifigure; /* we're at a new level */
i = findfigdimens(cp);
if (i != 0)
{
pi->UU.U8.preWid = (int32) floor(getnumber(&cp) * SPscale + 0.5);
pi->UU.U8.preHt = (int32) floor(getnumber(&cp) * SPscale + 0.5);
}
i = findfitsizes(cp);
if (i != 0)
{ /* with */
pi->UU.U8.postWid = (int32) floor(getnumber(&cp) * SPscale + 0.5);
pi->UU.U8.postHt = (int32) floor(getnumber(&cp) * SPscale + 0.5);
}
BackupInBuf(DVIMark() - specstart);
pushItem(multifigure - 1, pi);
return;
}
/* ---- ENDFIGURE ---- */
if (streq(nam, "endfigure", 3))
{
multifigure--;
if (multifigure < 0)
{
complain(ERRBAD);
fprintf(logfile, "Warning: Too many \"endfigure\"s !");
multifigure = 0;
}
BackupInBuf(DVIMark() - specstart);
if (multifigure == 0)
{
/* go do our set of figures (within figures...) */
figurehandle(pageitems, pageitems, 1);
free((char *)pageitems);/* #### should maybe garbage collect here */
pageitems = NULL;
} /* if */
return;
}
/* --- LINE --- */
if (streq(nam, "line", 3))
{
i = findscale(cp);
SPscale = thescaleof(i);
gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);
thk = getnumber(&cp); /* get the vector thickness */
if (thk < 1)
{
complain(ERRBAD);
fprintf(logfile, "?? Thickness not found. Setting to 1\n");
thk = 1;
}
i = findvectkind(cp);
vk = thevectorof(i);
i = findlinestyle(cp);
if (i != 0)
patt = thestyleof(getnumber(&cp));
else
patt = solid;
x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
minx = min(x1, x2);
maxx = max(x1, x2);
miny = min(y1, y2);
maxy = max(y1, y2);
BackupInBuf(DVIMark() - specstart);
cmd1byte(OURFONTFLAG);
linehandle(multifigure, SPscale, x1, y1, x2, y2, 0, 0, thk, vk, patt,
minx, maxx, miny, maxy, transx, transy, sx100, sy100, rot);
} /* line */
else if (streq(nam, "spline", 3) || streq(nam, "ttspline", 3))
{
i = findscale(cp);
SPscale = thescaleof(i);
gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);
if (streq(nam, "spline", 3))
{
thk = getnumber(&cp);
if (thk < 1)
{
complain(ERRBAD);
fprintf(logfile, "Spline Thickness not found. Setting to 1\n");
thk = 1;
}
}
i = findvectkind(cp);
vk = thevectorof(i);
i = findlinestyle(cp);
if (i != 0)
patt = thestyleof(getnumber(&cp));
else
patt = solid;
i = findsplinekind(cp);
if (i == 'b')
splinetype = BSPL;
else if (i == 'i')
splinetype = INTBSPL;
else if (i == 'k')
splinetype = CATROM;
else if (i == 'd')
splinetype = CARD;
else if (i == 0)
splinetype = CATROM;
i = findsplclosure(cp);
if (i == 'o')
isclosedspline = true;
else if (i == 'u')
isclosedspline = false;
else if (i == 0)
isclosedspline = false;
i = finddotmark(cp);
if (i == 'x')
markdiam = getnumber(&cp);
else if (i == 0)
markdiam = 0;
numknots = min(getnumber(&cp), (int32) MAXCTLPTS);
if (numknots < 1)
{
complain(ERRBAD);
fprintf(logfile,
"Number of spline/ttspline knot points not found. Setting to 1\n");
numknots = 1;
}
minx = TWO24;
miny = TWO24;
maxx = -TWO24;
maxy = -TWO24;
for (i = 0; i <= numknots + 3; i++)
{
cpts[i][0] = 0;
cpts[i][1] = 0;
} /* for */
for (i = 1; i <= numknots; i++)
{
x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
cpts[i][0] = x1;
if (x1 < minx)
minx = x1;
if (x1 > maxx)
maxx = x1;
y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
cpts[i][1] = y1;
if (y1 < miny)
miny = y1;
if (y1 > maxy)
maxy = y1;
} /* for */
if (streq(nam, "ttspline", 3))
{
for (i = 1; i <= numknots; i++)
TTary[i] = getnumber(&cp);
}
BackupInBuf(DVIMark() - specstart);
cmd1byte(OURFONTFLAG);
if (streq(nam, "spline", 3))
splinehandle(multifigure, SPscale, splinetype, isclosedspline, markdiam,
cpts, numknots, 0, 0, thk, vk, patt, minx, maxx, miny,
maxy, transx, transy, sx100, sy100, rot);
else
ttsplhandle(multifigure, SPscale, splinetype, isclosedspline, markdiam,
cpts, TTary, numknots, 0, 0, vk, patt, minx, maxx, miny,
maxy, transx, transy, sx100, sy100, rot);
}
else if (streq(nam, "beam", 4))
{
i = findscale(cp);
SPscale = thescaleof(i);
/* no transforms */
siz = getnumber(&cp); /* the staffsize */
i = findbeamkind(cp);
if (i == 'g')
bk = grace;
else if (i == 'r')
bk = regular;
else if (i == 0)
bk = regular;
x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
BackupInBuf(DVIMark() - specstart);
cmd1byte(OURFONTFLAG);
beamhandle(multifigure, siz, bk, x1, y1, x2, y2);
}
else if (streq(nam, "tieslur", 3))
{
i = findscale(cp);
SPscale = thescaleof(i);
minthk = getnumber(&cp);
if (minthk < 1)
{
complain(ERRBAD);
fprintf(logfile, "Tie/Slur Min Thickness not found. Setting to 1\n");
minthk = 1;
}
maxthk = getnumber(&cp);
if (maxthk < 1)
{
complain(ERRBAD);
fprintf(logfile, "Tie/Slur MaxThickness not found. Setting to 1\n");
maxthk = 1;
}
numknots = min(getnumber(&cp), (int32) MAXCTLPTS);
if (numknots < 1)
{
complain(ERRBAD);
fprintf(logfile,
"Tie/Slur Number of knot points not found. Setting to 1. Should be 5\n");
numknots = 1;
}
for (i = 1; i <= numknots; i++)
{
cpts[i][0] = (int32) floor(getnumber(&cp) * SPscale + 0.5);
cpts[i][1] = (int32) floor(getnumber(&cp) * SPscale + 0.5);
} /* for */
BackupInBuf(DVIMark() - specstart);
cmd1byte(OURFONTFLAG);
tieslurhandle(multifigure, cpts, numknots, (int) minthk, (int) maxthk);
}
else if (streq(nam, "arc", 3))
{
i = findscale(cp);
SPscale = thescaleof(i);
gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);
thk = getnumber(&cp);
if (thk < 1)
{
complain(ERRBAD);
fprintf(logfile, "Arc Thickness not found. Setting to 1\n");
thk = 1;
}
i = findvectkind(cp);
vk = thevectorof(i);
i = findlinestyle(cp);
if (i != 0)
patt = thestyleof(getnumber(&cp));
else
patt = solid;
radius = (int32) floor(getnumber(&cp) * SPscale + 0.5);
if (radius == 0)
radius = (int32) floor(1 * SPscale + 0.5);
i = findatsign(cp);
if (i != 0)
{
x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
}
else
{
x2 = 0;
y2 = 0; /* assume center at origin */
}
ang1 = getnumber(&cp);
if (abs(ang1) > 360)
{
ang1 %= 360;
/*
* p2c: x.p, line 5570: Note: Using % for possibly-negative arguments [317]
*/
}
ang2 = getnumber(&cp);
if (abs(ang2) > 360)
{
ang2 %= 360;
/*
* p2c: x.p, line 5573: Note: Using % for possibly-negative arguments [317]
*/
}
minx = TWO24;
miny = TWO24;
maxx = -TWO24;
maxy = -TWO24;
if (ang1 == ang2) /* a circle */
defineCircleCpts(radius, x2, y2, cpts, &numknots);
else /* a real arc */
definearcpts(radius, x2, y2, ang1, ang2, cpts, &numknots);
for (i = 1; i <= numknots; i++)
{
x1 = cpts[i][0];
if (x1 < minx)
minx = x1;
if (x1 > maxx)
maxx = x1;
y1 = cpts[i][1];
if (y1 < miny)
miny = y1;
if (y1 > maxy)
maxy = y1;
} /* for */
BackupInBuf(DVIMark() - specstart);
cmd1byte(OURFONTFLAG);
arccirclehandle(multifigure, SPscale, x2, y2, radius, ang1, ang2, cpts,
numknots, 0, 0, thk, vk, patt, minx, maxx, miny, maxy,
transx, transy, sx100, sy100, rot);
}
else if (streq(nam, "label", 3))
{
i = findscale(cp);
SPscale = thescaleof(i);
style = getnumber(&cp); /* font style number */
if (style < 1 || style > MAXLABELFONTS)
{
complain(ERRBAD);
fprintf(logfile, "Label style bad? Setting to Style 1\n");
style = 1;
}
x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
let = getletter(&cp);
while (let != '"')
let = getletter(&cp);
let = getanything(&cp); /* get next letter or whatever */
for (i = 0; let != '"'; ++i)
{ /* get the label phrase */
phrase[i] = let;
let = getanything(&cp); /* getletter; */
}
phrase[i] = '\0';
BackupInBuf(DVIMark() - specstart);
cmd1byte(OURFONTFLAG);
labelhandle(multifigure, SPscale, x1, y1, 0, 0, style, phrase, 0, 0);
}
else if (streq(nam, "param", 3))
{
i = getnumber(&cp); /* addressable param number */
fprintf(logfile, " I do not know what internal parameter #%ld is\n", i);
/* else */
BackupInBuf(DVIMark() - specstart);
}
else
{
complain(ERRNOTBAD);
fprintf(logfile, "Sorry, I don't know how to tyl %s\n", nam);
}
}
static int
otherspecials(cp)
char *cp;
{
fprintf(logfile, "Special: %s\n", cp);
return (1);
}
static void
mainhandlespecials(specnum, nbytes)
int32 specnum, nbytes;
{
/*
* specnum is the DVI-number of the special
* nbytes is the number of parameter bytes
*/
char sysnam[4];
char *cp, *buf;
int32 i;
char *malloc PP((unsigned));
int free PP((char *));
specstart = DVIMark() - specnum + 237;
ourxpos = h;
ourypos = v; /* note the global DVI (h,v) coords */
cp = buf = malloc((unsigned)(nbytes + 1));
for (i = 0; i < nbytes; ++i)
cp[i] = Dget1byte();
cp[i] = '\0';
while (isspace(*cp))
++cp;
/* get the name of the system --- Hopefully 'tyl' */
for (i = 0; *cp != '\0' && *cp != ' '; ++cp)
if (i < 3)
sysnam[i++] = tolowercase(*cp);
sysnam[i] = '\0'; /* end of string */
if (streq(sysnam, "tyl", 3))
tylspecials(cp);
else if (otherspecials(buf))
;
else
fprintf(logfile, "Unknown special ignored: %s\n", buf);
free((char *)buf);
}
/*
* ==================================================
*
* The routines below assume coordinates are already in 4th Quadrant DVI-space
*
* =====================================================
*/
/*
* returns 0 if dy.dx not in font 1 if ok 2 if ok and caller should use two of the "code"s coding scheme requires 0<= [dx, dy]
* <= 16 AND that max(dx, abs(dy)) is in [0,1,2,4,8,16]
*/
static int32
outvector(dx, dy, code)
int32 dx, dy, *code;
{
int32 c, result;
if (dx < 0)
return (0);
result = 0; /* init for potential failure */
*code = -1;
if (dy < 0)
c = dy + dx - max(dx, -dy) * 9 + 160;
else
c = dy - dx - max(dx, dy) * 7 + 160;
/*
* here translate to OUR coding scheme and return the correct number
* this is needed because "c" thinks the char range
* is 0 to 160, while we have only 128 chars
*/
if (c == 0)
{ /* special cases */
*code = 63;
result = 2;
}
else if (c == 64)
{
*code = 95;
result = 2;
}
else
{
result = 1; /* just one char is fine */
if (c >= 1 && c <= 63) /* c - 33 */
*code = c - 1;
else if (c >= 80 && c <= 112)
*code = c - 17;
else if (c >= 120 && c <= 136)
*code = c - 24;
else if (c >= 140 && c <= 148)
*code = c - 27;
else if (c >= 150 && c <= 154)
*code = c - 28;
else if (c == 160)
*code = 127;
}
return result;
}
/* take care of a Manhattan (horizontal /vertical) line */
static void
hvline(lx, by, rx, ty, fontindex)
int32 lx, by, rx, ty, fontindex;
{
int32 t, rth, x, y, width, height;
rth = VFontTable[fontindex - 1]->PenSize; /* thickness of vector in sp */
if (lx == rx)
{ /* Vertical line */
if (ty > by)
{
t = by;
by = ty;
ty = t; /* swap */
}
x = (int32) floor(lx - rth / 2.0 + 0.5);
y = by;
width = rth;
height = by - ty;
}
else
{ /* Horizontal line */
if (ty < by)
{
t = by;
by = ty;
ty = t; /* swap */
}
if (lx > rx)
{
t = lx;
lx = rx;
rx = t; /* swap */
}
x = lx;
y = by + rth / 2; /* + rth for {h,v}-space */
width = rx - lx;
height = rth;
}
isetpos(x, y);
cmd1byte(PUTRULE);
cmd4byte(height);
cmd4byte(width);
/*
* output two dots on ends of the rules at lx, by and rx, ty
*/
/* the font has already been set before these calls */
Tyldot(lx, by);
Tyldot(rx, ty);
isetpos(rx, ty);
}
/* Local variables for diagonal: */
struct LOC_diagonal
{
int32 xl, yb, xr, yt, curx, cury;
double slope;
ScaledPts mxveclen;
};
/* compute maximum length vector character that we can use */
static void
getincr(outdx, outdy, LINK)
int32 *outdx, *outdy;
struct LOC_diagonal *LINK;
{
int32 radius, x, y, sign;
radius = LINK->mxveclen;/* radius of semi-square */
/*
* make sure the pt is outside of the semi-square, scaling down radius if necessary
*/
while (LINK->xr - LINK->curx < radius &&
abs(LINK->yt - LINK->cury) < radius)
radius /= 2;
if (LINK->slope < 0.0) /* <0 since in 4th quad by now */
sign = -1;
else
sign = 1;
if (LINK->xr == LINK->curx)
{
*outdx = 0;
*outdy = sign * radius;
return;
}
if (LINK->yt == LINK->cury)
{
*outdx = abs(radius);
*outdy = 0;
return;
}
/*
* compute the intersection with the semi-square, choose whichever slope is best
*/
if (fabs(LINK->slope) < 1.0)
{ /* mostly horizontal */
*outdx = abs(radius);
y = LINK->yb +
(int32) floor((LINK->curx + abs(radius) - LINK->xl) * LINK->slope + 0.5);
*outdy = y - LINK->cury;
}
else
{ /* mostly vertical */
x = LINK->xl +
(int32) floor((LINK->cury + sign * radius - LINK->yb) / LINK->slope + 0.5);
*outdx = x - LINK->curx;
*outdy = sign * radius;
}
if (abs(*outdy) > abs(LINK->yt - LINK->cury)) /* truncate */
*outdy = LINK->yt - LINK->cury;
if (*outdx > LINK->xr - LINK->curx) /* truncate */
*outdx = LINK->xr - LINK->curx;
if (*outdx < 0)
*outdx = 0;
/*
* method to find the exact intersection of the line segment with the semi-circle, used to determine the x and y
* values:: we do this by using the arctangent of the slope as the angle 'a' from the x-axis. Then use the relation y =
* r cos a, and x = r sin a we can be smart about all this trig stuff by using the relation : sin (arctan a) = 1/sqrt(1
* + a^2) cos (arctan a) = a/sqrt(1 + a^2) Thus: q := (1.0 / sqrt (slope * slope + 1.0)); outdx := round (q * radius);
* outdy := round (q * radius * slope);
*
* Unfortunately, we cannot access the Vector Font coding scheme because the outdx, outdy 's produced here do no conform
* to the condition max (dx, abs(dy)) in [0,1,2,4,8,16] when converted to vector-font sizes with sptovecs (see the
* 'diagonal' proc.).
*/
}
static void
diagonal(xl_, yb_, xr_, yt_, fontindex)
int32 xl_, yb_, xr_, yt_, fontindex;
{
struct LOC_diagonal V;
int32 t, dx, dy, code;
double sptovecs;
ScaledPts rho;
V.xl = xl_;
V.yb = yb_;
V.xr = xr_;
V.yt = yt_;
if (V.xr != V.xl) /* some illegal value */
V.slope = (double) (V.yt - V.yb) / (V.xr - V.xl);
else
V.slope = BIGREAL;
if (V.xl > V.xr)
{
t = V.xl;
V.xl = V.xr;
V.xr = t;
t = V.yb;
V.yb = V.yt;
V.yt = t;
} /* swap */
V.curx = V.xl;
V.cury = V.yb;
V.mxveclen = VFontTable[fontindex - 1]->MaxVectLen;
rho = V.mxveclen / 16; /* minimum radius of vector fonts */
if (rho == 0)
{
complain(ERRREALBAD);
fprintf(logfile,
"Diagonal: Min radius of vector font is zero. setting to 1\n");
rho = 1;
}
if (abs(V.xl - V.xr) <= rho && abs(V.yb - V.yt) <= rho)
{ /* pretty much a null line */
Tyldot(V.xl, V.yb);
return;
}
sptovecs = 1.0 / rho; /* conversion for scaled pts to vectorfont units */
code = -1; /* initialize to a bogus number */
/*
* this conditional really has to have "or" instead of "and", because of lines that are nearly* horizontal or vertical
*/
while (V.xr - V.curx >= rho || abs(V.yt - V.cury) >= rho)
{
getincr(&dx, &dy, &V);
/*
* Get the vector character code corresponding to this approximate incremental amount
*/
t = outvector((int32) floor(dx * sptovecs + 0.5),
(int32) floor(dy * sptovecs + 0.5), &code);
/*
* Now that we have the character code, go find out its actual physical dimensions for the real dy/dx amounts
*/
if (dy > 0)
dy = VFontTable[fontindex - 1]->FontInfo[code].Cdp;
else
dy = -VFontTable[fontindex - 1]->FontInfo[code].Cht;
dx = VFontTable[fontindex - 1]->FontInfo[code].Cwd;
switch (t)
{
case 0:
complain(ERRREALBAD);
fprintf(logfile, "Error in Diagonal:: bad dydx\n");
break;
case 1:
isetpos(V.curx, V.cury);
iputchar(code);
break;
case 2:
isetpos(V.curx, V.cury);
iputchar(code);
isetpos(V.curx + dx / 2, V.cury + dy / 2);
iputchar(code);
break;
} /* case */
V.curx += dx;
V.cury += dy;
} /* while */
/*
* Get the approximate incremental amount. We use this dy/dx pair in order to index into our vector font coding scheme
*/
if (code >= 0 && V.xr - V.curx >= rho && abs(V.yt - V.cury) >= rho)
iputchar(code);
/* not null line */
}
/* Local variables for tylBrokenLine: */
struct LOC_tylBrokenLine
{
int32 fontindex;
LineStyle line_type;
int useXaxis;
int32 a0, b0, a1, b1, a2, a3, b2, b3, gap, dot, dash;
double s, z;
int32 J, frame, Dotgap, Dotdot, Dashgap, Dashdash, DDotgap, DDotdot, DDotdash;
};
static void
spread(lt, extra, T, LINK)
LineStyle lt;
int32 extra, T;
struct LOC_tylBrokenLine *LINK;
{
if (T == 0)
{ /* only partial frame fits */
if (LINK->useXaxis)
diagonal(LINK->a0, LINK->b0, LINK->a1, LINK->b1, LINK->fontindex);
else
diagonal(LINK->b0, LINK->a0, LINK->b1, LINK->a1, LINK->fontindex);
return;
}
LINK->J = 0;
LINK->s = float_(LINK->b1 - LINK->b0) / float_(LINK->a1 - LINK->a0);
LINK->z = float_(extra) / float_(T);
switch (lt)
{
case dotted:
do
{
LINK->a2 = LINK->a0 + LINK->J * LINK->frame;
if (extra > 0)
LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5);
LINK->a3 = LINK->a2 + LINK->dot;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
}
LINK->J++;
} while (LINK->a3 < LINK->a1);
break;
case dashed:
do
{
LINK->a2 = LINK->a0 + LINK->J * LINK->frame;
if (extra > 0)
LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5);
LINK->a3 = LINK->a2 + LINK->dash;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
}
LINK->J++;
} while (LINK->a3 < LINK->a1);
break;
case dotdash:
do
{
LINK->a2 = LINK->a0 + LINK->J * LINK->frame;
if (extra > 0)
LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5);
LINK->a3 = LINK->a2 + LINK->dash;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
LINK->a2 = LINK->a3 + LINK->gap;
if (extra > 0)
LINK->a2 += (int32) floor(LINK->z * 0.5 + 0.5);
LINK->a3 = LINK->a2 + LINK->dot;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
}
}
LINK->J++;
} while (LINK->a3 < LINK->a1);
break;
}
} /* spread */
static void
balance(lt, extra, T, LINK)
LineStyle lt;
int32 extra, T;
struct LOC_tylBrokenLine *LINK;
{
if (T == 0)
{ /* only partial frame fits */
if (LINK->useXaxis)
diagonal(LINK->a0, LINK->b0, LINK->a1, LINK->b1, LINK->fontindex);
else
diagonal(LINK->b0, LINK->a0, LINK->b1, LINK->a1, LINK->fontindex);
return;
}
LINK->J = 0;
LINK->s = float_(LINK->b1 - LINK->b0) / float_(LINK->a1 - LINK->a0);
switch (lt)
{
case dashed:
do
{
LINK->a2 = LINK->a0 + LINK->J * LINK->frame - extra / 2;
LINK->a3 = LINK->a2 + LINK->dash;
if (LINK->J == 0)
LINK->a2 = LINK->a0;
if (LINK->a3 > LINK->a1)
LINK->a3 = LINK->a1;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
}
LINK->J++;
} while (LINK->a3 < LINK->a1);
break;
case dotdash:
do
{
LINK->a2 = LINK->a0 + LINK->J * LINK->frame - extra / 2;
LINK->a3 = LINK->a2 + LINK->dash;
if (LINK->J == 0)
LINK->a2 = LINK->a0;
if (LINK->a3 > LINK->a1)
LINK->a3 = LINK->a1;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
LINK->a2 = LINK->a3 + LINK->gap;
LINK->a3 = LINK->a2 + LINK->dot;
LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
if (LINK->a3 <= LINK->a1)
{
if (LINK->useXaxis)
diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
else
diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
}
}
LINK->J++;
} while (LINK->a3 < LINK->a1);
break;
}
} /* balance */
static int32
project(I, LINK)
int32 I;
struct LOC_tylBrokenLine *LINK;
{
int32 K; /* gives the projection of lengths onto axes */
K = (int32) floor(I * float_(abs(LINK->a1 - LINK->a0)) / LINK->s + 0.5);
if (K == 0)
K = 1;
return K;
}
static void
setlengths(findex, LINK)
int32 findex;
struct LOC_tylBrokenLine *LINK;
{
/* sets the "optimal" sizes for textured lines */
int32 penrad;
VThickness siz;
penrad = VFontTable[findex - 1]->PenSize;
siz = VFontTable[findex - 1]->psize;
LINK->Dotdot = penrad / siz;
LINK->Dotgap = penrad * 6;
LINK->Dashdash = penrad * 6;
LINK->Dashgap = penrad * 6;
LINK->DDotdash = penrad * 6;
LINK->DDotgap = penrad * 4;
LINK->DDotdot = penrad / siz;
}
static void
setframesize(LINK)
struct LOC_tylBrokenLine *LINK;
{
switch (LINK->line_type)
{
/* length of frame depends on type of broken line */
case solid:
LINK->frame = 0;
break;
case dotted:
LINK->frame = LINK->gap + LINK->dot;
break;
case dashed:
LINK->frame = LINK->gap + LINK->dash;
break;
case dotdash:
LINK->frame = LINK->gap * 2 + LINK->dot + LINK->dash;
break;
}
}
static void
tylBrokenLine(x0, y0, x1, y1, fontindex_, line_type_)
int32 x0, y0, x1, y1, fontindex_;
LineStyle line_type_;
{
struct LOC_tylBrokenLine V;
double fit;
int32 T, a1ma0;
V.fontindex = fontindex_;
V.line_type = line_type_;
if (x0 == x1 && y0 == y1)
{
diagonal(x0, y0, x1, y1, V.fontindex); /* null line */
return;
}
setlengths(V.fontindex, &V);
if (abs(y1 - y0) > abs(x1 - x0))
{ /* longer axis is used as base */
V.useXaxis = false;
V.a0 = y0;
V.b0 = x0;
V.a1 = y1;
V.b1 = x1;
}
else
{
V.useXaxis = true;
V.a0 = x0;
V.b0 = y0;
V.a1 = x1;
V.b1 = y1;
}
/* the distance between a0 and a1 is now greater than that between b0 and b1. */
/* redefine distances as integral units along axes */
V.s = distance(float_(V.a0), float_(V.b0), float_(V.a1), float_(V.b1));
switch (V.line_type)
{
case solid:
/* blank case */
break;
case dotted:
V.gap = project(V.Dotgap, &V);
V.dot = project(V.Dotdot, &V);
break;
case dashed:
V.gap = project(V.Dashgap, &V);
V.dash = project(V.Dashdash, &V);
break;
case dotdash:
V.gap = project(V.DDotgap, &V);
V.dot = project(V.DDotdot, &V);
V.dash = project(V.DDotdash, &V);
break;
}
/*
* ensure direction of line is from smaller to larger along the longer axis
*/
if (V.a0 > V.a1)
{
V.J = V.a0;
V.a0 = V.a1;
V.a1 = V.J;
V.J = V.b0;
V.b0 = V.b1;
V.b1 = V.J;
}
setframesize(&V);
a1ma0 = V.a1 - V.a0;
/* fit is the number of frames that fit in line */
if (V.frame != 0)
fit = float_(a1ma0) / float_(V.frame);
else
fit = 1.0;
if (fit >= 1.0)
T = (int32) floor(fit + 0.5);
else
{
/* change frame elements (dot, dash, gap) since frame is too large */
switch (V.line_type)
{
case dotted:
V.gap += a1ma0 - V.frame;
if (V.gap < V.dot)
return; /* exit */
setframesize(&V);
break;
case dashed:
case dotdash:
/* idea:decrease gap; if too small then shrink dash and refigure gap */
if (V.frame - a1ma0 > V.gap / 2)
{
V.dash = (int32) floor(V.dash * fit * 0.80 + 0.5);
V.gap = (int32) floor(V.gap * fit + 0.5);
setframesize(&V);
}
V.gap += a1ma0 - V.frame;
if (V.line_type == dotdash)
V.gap /= 2;
if (V.gap < V.dot)
return; /* exit */
setframesize(&V);
break;
} /* case */
T = 1; /* NOW it will fit */
} /* else */
switch (V.line_type)
{
case solid:
if (V.useXaxis)
diagonal(V.a0, V.b0, V.a1, V.b1, V.fontindex);
else
diagonal(V.b0, V.a0, V.b1, V.a1, V.fontindex);
break;
case dotted: /* dotted lines begin and end on a dot */
if (T * V.frame + V.dot == a1ma0)
spread(dotted, 0, T, &V);
else if (T * V.frame + V.dot > a1ma0)
{
/*
* gap := gap - ((T*frame+dot)-a1ma0); {
*/
spread(dotted, a1ma0 - T * V.frame - V.dot, T, &V);
/*
* spread(dotted, a1ma0 - (T-1)*frame - dot, T-1); {
*/
}
else
spread(dotted, a1ma0 - T * V.frame - V.dot, T, &V);
break;
case dashed:
/*
* dashed lines begin and end on dash : the beginning and ending dashes are at least half the dash length
* int32.
*/
if (T * V.frame + V.dash == a1ma0)
spread(dashed, 0, T, &V);
else if (T * V.frame + V.dash > a1ma0)
balance(dashed, T * V.frame + V.dash - a1ma0, T, &V);
else
spread(dashed, a1ma0 - T * V.frame - V.dash, T, &V);
break;
case dotdash:
/*
* if ending on a dash then beginning and ending dashes are half the dash length long - final dots are full
* dot length
*/
if (T * V.frame + V.dash == a1ma0)
spread(dotdash, 0, T, &V);
else if (T * V.frame + V.dash + V.gap + V.dot == a1ma0)
spread(dotdash, 0, T, &V);
else if (T * V.frame + V.dash > a1ma0)
balance(dotdash, T * V.frame + V.dash - a1ma0, T, &V);
else if (T * V.frame + V.dash + V.gap + V.dot > a1ma0)
spread(dotdash, a1ma0 - T * V.frame - V.dash, T, &V);
else
spread(dotdash, a1ma0 - T * V.frame - V.dash - V.gap - V.dot, T, &V);
break;
}
}
void
clampthickness(thic)
VThickness *thic;
{
/*
* #### this is just a simple clamp really should be something like: while not (thic in set_of_appropriate_thicknesses)
* do modify thic and try again
*/
if (*thic <= LoVThick)
*thic = LoVThick + 1;
while (((1 << (*thic)) & 0x1ffe) == 0 && *thic <= HiVThick)
(*thic)++;
if (*thic > HiVThick)
*thic = HiVThick;
}
static void
slurclamp(thic, totpts)
VThickness *thic;
int32 totpts;
{
/*
* this post-clamps the sampled thicknesses calculated over the whole of the spline
*/
int32 i, oneseventh, middle, startval, endval;
double deltaval, val, incrval, alpha, alphaincr;
/*
* $$ NOTE:: How does the ttspline interpolation of thicknesses compare to the below results?? Can we avoid having it
* done elsewhere and concentrate on it here??
*/
oneseventh = (int32) floor(totpts / 7.0 + 0.5);
for (i = 1; i <= oneseventh; i++)
thic[i] = thic[1];
for (i = oneseventh * 6; i <= totpts; i++)
thic[i] = thic[totpts];
middle = (int32) floor(totpts / 2.0 + 0.5);
for (i = oneseventh * 3; i <= oneseventh * 4; i++)
thic[i] = thic[middle];
startval = thic[oneseventh - 1];
endval = thic[oneseventh * 3 + 1];
deltaval = (endval - startval) * 2.0 / (oneseventh * 2);
alphaincr = PI / (oneseventh * 2 + 1);
alpha = PI;
val = float_(startval);
for (i = oneseventh; i < oneseventh * 3; i++)
{ /* interpolate: ease in from minthick to middlethickness */
alpha += alphaincr;
incrval = (cos(alpha) + 1.0) / 2.0 * deltaval;
val += incrval;
thic[i] = (int32) floor(val + 0.5);
}
startval = thic[oneseventh * 4 - 1];
endval = thic[oneseventh * 6 + 1];
deltaval = (endval - startval) * 2.0 / (oneseventh * 2);
alphaincr = PI / (oneseventh * 2 + 1);
alpha = 0.0;
val = float_(startval);
for (i = oneseventh * 4 + 1; i <= oneseventh * 6; i++)
{ /* ease out from middle thickness to min thick at far end */
alpha += alphaincr;
incrval = (cos(alpha) + 1.0) / 2.0 * deltaval;
val += incrval;
thic[i] = (int32) floor(val + 0.5);
}
}
void
layline(xl, yb, xr, yt, fontindex, pattern, useVecfontOnly)
int32 xl, yb, xr, yt, fontindex;
LineStyle pattern;
int useVecfontOnly;
{
int32 t;
if (xr < xl)
{
t = xr;
xr = xl;
xl = t;
t = yb;
yb = yt;
yt = t;
}
isetfont(VFontTable[fontindex - 1]->DVIFontNum);
/*
* we may want to require using a vector font only, instead of a combination of vectors and TeX-rules. It may look
* better this way.
*/
if (useVecfontOnly)
{
tylBrokenLine(xl, yb, xr, yt, fontindex, pattern);
return;
}
if ((xl != xr || yb != yt) && (xl == xr || yb == yt))
{ /* Null or diagonal lines */
/*
* if (pattern = solid) then hvline (xl, yb, xr, yt, fontindex) (* make use of rules *) else USENORULES
*/
tylBrokenLine(xl, yb, xr, yt, fontindex, pattern);
return;
}
if (pattern == solid)
diagonal(xl, yb, xr, yt, fontindex);
else
tylBrokenLine(xl, yb, xr, yt, fontindex, pattern);
/* be smart about the lines */
}
#define DontDoThicks false
#define VectorsOnly true
/* Local variables for layAspline: */
struct LOC_layAspline
{
VThickness thick;
};
void
layAspline(thetype, isclosed, isanArc, domarks, cpts, numpts,
thick_, vkind, patt)
SplineKind thetype;
int isclosed, isanArc;
int32 domarks;
int32(*cpts)[2];
int32 numpts;
VThickness thick_;
VectKind vkind;
LineStyle patt;
{
struct LOC_layAspline V;
SplineSegments pointList;
int32 i, xs, ys;
ThickAryType tt1, tt2;
VecIndex F;
int32 FORLIM;
V.thick = thick_;
clampthickness(&V.thick);
for (i = 0; i <= numpts + 3; i++)
tt1[i] = V.thick;
/* do any marks if necessary to show the control points */
if (domarks > 0)
{
F = GetVectFont((int) domarks, VKCirc);
isetfont(VFontTable[F - 1]->DVIFontNum);
for (i = 1; i <= numpts; i++)
Tyldot(cpts[i][0], cpts[i][1]);
}
drawSpline(thetype, isclosed, isanArc, patt, numpts, cpts, pointList,
DontDoThicks, tt1, tt2);
F = GetVectFont(V.thick, vkind);
xs = pointList[0][0];
ys = pointList[0][1];
FORLIM = lastPoint;
for (i = 1; i < FORLIM; i++)
{
layline(xs, ys, pointList[i][0], pointList[i][1], F, patt, VectorsOnly);
xs = pointList[i][0];
ys = pointList[i][1];
}
if (isclosed) /* complete the motion */
layline(pointList[lastPoint - 1][0], pointList[lastPoint - 1]
[1], pointList[0][0], pointList[0][1], F, patt, VectorsOnly);
}
#define NotAnArc false
#define DoThicksToo true
#define VectorsOnly true
void
layNspline(thetype, isclosed, isitaslur, domarks, cpts, numpts,
thickmatrix, vkind, patt)
SplineKind thetype;
int isclosed, isitaslur;
int32 domarks;
int32(*cpts)[2];
int32 numpts;
VThickness *thickmatrix;
VectKind vkind;
LineStyle patt;
{
SplineSegments pointList;
int32 i, xs, ys;
VThickness ts;
ThickAryType tt;
VecIndex F;
int32 FORLIM;
/* do any marks if necessary to show the control points */
if (domarks > 0)
{
F = GetVectFont((int) domarks, VKCirc);
isetfont(VFontTable[F - 1]->DVIFontNum);
for (i = 1; i <= numpts; i++)
Tyldot(cpts[i][0], cpts[i][1]);
}
drawSpline(thetype, isclosed, NotAnArc, patt, numpts, cpts, pointList,
DoThicksToo, thickmatrix, tt);
if (isitaslur && !skiptsclamp)
slurclamp(tt, lastPoint); /* which kind of clamping to use */
xs = pointList[0][0];
ys = pointList[0][1];
ts = tt[1];
FORLIM = lastPoint;
for (i = 1; i < FORLIM; i++)
{
clampthickness(&ts);
F = GetVectFont(ts, vkind);
layline(xs, ys, pointList[i][0], pointList[i][1], F, patt, VectorsOnly);
xs = pointList[i][0];
ys = pointList[i][1];
ts = tt[i + 1];
}
if (!isclosed)
return;
ts = tt[lastPoint];
clampthickness(&ts);
F = GetVectFont(ts, vkind);
layline(pointList[lastPoint - 1][0], pointList[lastPoint - 1]
[1], pointList[0][0], pointList[0][1], F, patt, VectorsOnly);
}
/* && start dvidvi section */
/*-----------------------------------------------------*/
static void
initialize()
{
initVnMnLtables();
multifigure = 0;
pgfigurenum = 0;
TotBytesWritten = 0;
ourq = 0;
currpagenum = 0;
FTBDs = 0;
InitDVIBuf();
inpostamble = false;
didnewfonts = false;
skiptsclamp = false;
ErrorOccurred = false;
}
/*-----------------------------------------------------*/
static int
inTFM(z)
int32 z;
{
int32 k, lh, nw, alpha, beta, FORLIM;
fontinfo *WITH;
readtfmword();
lh = b2 * 256 + b3;
readtfmword();
font[nf].bc = b0 * 256 + b1;
font[nf].ec = b2 * 256 + b3;
if (font[nf].ec < font[nf].bc)
font[nf].bc = font[nf].ec + 1;
readtfmword();
nw = b0 * 256 + b1;
if (nw == 0 || nw > 256)
return (false);
for (k = 1; k <= lh + 3; k++)
{
if (feof(tfmfile))
return (false);
readtfmword();
if (k == 4)
{
if (b0 < 128)
tfmchecksum = ((b0 * 256 + b1) * 256 + b2) * 256 + b3;
else
tfmchecksum = (((b0 - 256) * 256 + b1) * 256 + b2) * 256 + b3;
}
}
FORLIM = font[nf].ec - font[nf].bc;
for (k = 0; k <= FORLIM; k++)
{
readtfmword();
if (b0 > nw)
return (false);
font[nf].widths[k] = b0;
}
alpha = z * 16;
beta = 16;
while (z >= TWO23)
{
z /= 2;
beta /= 2;
}
for (k = 0; k < nw; k++)
{
readtfmword();
inwidth[k] = ((b3 * z / 256 + b2 * z) / 256 + b1 * z) / beta;
if (b0 > 0)
{
if (b0 < 255)
return (false);
inwidth[k] -= alpha;
}
}
if (inwidth[0] != 0)
return (false);
WITH = &font[nf]; /* with */
FORLIM = WITH->ec - WITH->bc;
for (k = 0; k <= FORLIM; k++)
{
if (WITH->widths[k] == 0)
{
WITH->widths[k + WITH->bc] = TWO31;
/* pixelwidths[k + bc] := 0; */
}
else
{
WITH->widths[k + WITH->bc] = inwidth[WITH->widths[k]];
/* pixelwidths[k + bc] := round(conv * widths[k]); */
}
}
return (true);
}
static void
Fastdefinefont(fn)
int32 fn;
{
int32 p, k, n;
(void) Dsign4byte();
(void) Dsign4byte();
(void) Dsign4byte();
p = Dget1byte();
n = Dget1byte();
for (k = 1; k <= p + n; k++)
(void) Dget1byte();
} /* Fastdefinefont */
static void
definefont(e)
int32 e;
{
char f;
int32 p, k, n, c, q, d;
charstring tfmname;
if (nf == MAXFONTS)
{
complain(ERRREALBAD);
fprintf(logfile, "TeXtyl capacity exceeded (max fonts=%d)!\n",
MAXFONTS);
jumpout();
}
font[nf].num = e;
f = 0;
while (font[f].num != e)/* find first occurrence */
f++;
c = Dsign4byte();
font[nf].checksum = c;
q = Dsign4byte();
font[nf].scaledsize = q;
d = Dsign4byte();
font[nf].designsize = d;
p = Dget1byte();
n = Dget1byte();
for (k = 0; k < p + n; k++)
font[nf].name[k] = Dget1byte();
font[nf].name[k] = '\0';
if (f != nf) /* f = nf */
return;
strcpy(tfmname, font[nf].name);
strcat(tfmname, ".tfm");
if (!opentfmfile(tfmname))
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loaded, TFM file can't be opened!\n", tfmname);
jumpout();
return;
}
if (q <= 0 || q >= TWO27)
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loaded, bad scale (%d)!\n", tfmname, q);
return;
}
if (d <= 0 || d >= TWO27)
{
complain(ERRREALBAD);
fprintf(logfile, "%s---not loaded, bad design size (%d)!\n", tfmname, d);
return;
}
if (!inTFM(q))
{ /* intfm */
complain(ERRREALBAD);
fprintf(logfile, "%s---not loaded, TFM file is bad\n", tfmname);
return;
} /* intfm */
font[nf].space = q / 6;
if (c != 0 && tfmchecksum != 0 && c != tfmchecksum)
{
fprintf(logfile, "Problem in fig#%d on page %d\n",
pgfigurenum, currpagenum);
fprintf(logfile, "%s---beware: check sums do not agree!\n", tfmname);
fprintf(logfile, " (%d vs. %d)\n", c, tfmchecksum);
}
d = (int32) floor(100.0 * conv * q / (trueconv * d) + 0.5);
nf++;
font[nf].space = 0;
}
static int32
firstpar(o)
int o;
{
int32 fpar;
if (0 <= o && o <= 127)
fpar = o;
else if (171 <= o && o <= 234)
fpar = o - 171;
else
switch (o)
{
case 128:
case 133:
case 235:
case 239:
case 243:
fpar = Dget1byte();
break;
case 129:
case 134:
case 236:
case 240:
case 244:
fpar = Dget2byte();
break;
case 130:
case 135:
case 237:
case 241:
case 245:
fpar = Dget3byte();
break;
case 143:
case 148:
case 153:
case 157:
case 162:
case 167:
fpar = Dsign1byte();
break;
case 144:
case 149:
case 154:
case 158:
case 163:
case 168:
fpar = Dsign2byte();
break;
case 145:
case 150:
case 155:
case 159:
case 164:
case 169:
fpar = Dsign3byte();
break;
case 131:
case 132:
case 136:
case 137:
case 146:
case 151:
case 156:
case 160:
case 165:
case 170:
case 238:
case 242:
case 246:
fpar = Dsign4byte();
break;
case 138:
case 139:
case 140:
case 141:
case 142:
case 247:
case 248:
case 249:
case 250:
case 251:
case 252:
case 253:
case 254:
case 255:
fpar = 0;
break;
case 147:
fpar = w;
break;
case 152:
fpar = x;
break;
case 161:
fpar = y;
break;
case 166:
fpar = z;
break;
}
return fpar;
}
static int
specialcases(o, p)
int32 o, p;
{
if (o < 157 || o > 249)
{
complain(ERRREALBAD);
fprintf(logfile, "undefined command %d!\n", o);
return (true);
}
else if (171 <= o && o <= 238)
{
font[nf].num = p;
curfont = 0;
while (font[curfont].num != p)
curfont++;
return (true);
}
switch (o)
{
case 157:
case 158:
case 159:
case 160:
break;
case 161:
case 162:
case 163:
case 164:
case 165:
y = p;
break;
case 166:
case 167:
case 168:
case 169:
case 170:
z = p;
break;
case 243:
case 244:
case 245:
case 246:
definefont(p);
return (true);
case 239:
case 240:
case 241:
case 242: /* =========specials============= */
mainhandlespecials(o, p);
return (true);
case 247:
complain(ERRREALBAD);
fprintf(logfile, "preamble command within a page!\n");
return (false);
case 248:
case 249:
complain(ERRREALBAD);
fprintf(logfile, "postamble command within a page!\n");
return (false);
}
if (v > 0 && p > 0)
{
if (v > TWO31 - p)
p = TWO31 - v;
}
if (v < 0 && p < 0)
{
if (-v > p + TWO31)
p = -v - TWO31;
}
v += p;
return (true);
}
static int
dopage()
{
int32 o, p, q;
struct stackrec *WITH;
curfont = nf;
s = 0;
h = 0;
v = 0;
w = 0;
x = 0;
y = 0;
z = 0;
ourxpos = 0;
ourypos = 0;
ourfontnum = -1;
for (;;)
{
o = Dget1byte();
p = firstpar(o);
if (feof(dvifile))
{
fprintf(logfile, "Bad DVI file: the file ended prematurely!\n");
jumpout();
}
if (o <= 131)
goto _L41;
if (o > 156)
{
if (specialcases(o, p))
continue;
else
return (false);
}
switch (o)
{
case 133:
case 134:
case 135:
case 136:
goto _L41;
break;
case 132:
case 137:
goto _L42;
break;
case 138:
continue;
case 139: /* BOP */
complain(ERRREALBAD);
fprintf(logfile, "bop occurred before eop\n");
return (false); /* Fail */
break;
case 140: /* EOP */
if (s != 0)
{
complain(ERRREALBAD);
fprintf(logfile, "stack not empty at end of page (level %d)!\n", s);
}
if (multifigure != 0)
{
complain(ERRBAD);
fprintf(logfile,
"Some figure definition not closed at end of page %d!\n",
currpagenum);
}
fprintf(logfile, "%d]", currpagenum);
if (currpagenum % 10 == 0)
putc('\n', logfile);
return (true);
case 141: /* PUSH */
WITH = &stack[s]; /* with */
WITH->sh = h;
WITH->sv = v;
WITH->sw = w;
WITH->sx = x;
WITH->sy = y;
WITH->sz = z;
s++;
continue;
case 142: /* POP */
if (s == 0)
{
complain(ERRREALBAD);
fprintf(logfile, "illegal pop at level zero!\n");
}
else
{
s--;
WITH = &stack[s];
h = WITH->sh;
v = WITH->sv;
w = WITH->sw;
x = WITH->sx;
y = WITH->sy;
z = WITH->sz;
}
continue;
case 143:
case 144:
case 145:
case 146:
q = p;
goto _L43;
break;
case 147:
case 148:
case 149:
case 150:
case 151:
w = p;
q = p;
goto _L43;
break;
case 152:
case 153:
case 154:
case 155:
case 156:
x = p;
q = p;
goto _L43;
break;
} /* case */
_L41: /* finish cmd to set/put a char */
if (p < 0)
p = 255 - ((-p - 1) & 255);
else if (p >= 256)
p &= 255;
if (p < font[curfont].bc || p > font[curfont].ec)
q = TWO31;
else
q = font[curfont].widths[p];
if (q == TWO31)
{
complain(ERRREALBAD);
fprintf(logfile, "Character %d invalid in font #%d\n", p, curfont);
}
if (o >= 133)
continue;
if (q == TWO31)
q = 0;
goto _L43;
_L42: /* finish cmd to set/put rule */
q = Dsign4byte();
if (o == 137)
continue;
goto _L43;
_L43: /* finish cmd that sets h += q */
if (h > 0 && q > 0)
{
if (h > TWO31 - q)
q = TWO31 - h;
}
if (h < 0 && q < 0)
{
if (-h > q + TWO31)
q = -h - TWO31;
}
h += q;
}
}
static void
skippages()
{
int32 p;
int32 k;
for (;;)
{
if (feof(dvifile))
{
fprintf(logfile, "Bad DVI file: the file ended prematurely!\n");
jumpout();
}
k = Dget1byte();
p = firstpar(k);
switch (k)
{
case 139: /* BOP */
newbackptr = DVIMark() + TotBytesWritten - 1;
currpagenum = Dsign4byte(); /* count[0] */
for (k = 1; k <= 9; k++) /* WAS count[k] := */
(void) Dsign4byte();
(void) Dsign4byte();
BackupInBuf(4);
cmdSigned(oldbackptr, 4);
oldbackptr = newbackptr;
fprintf(logfile, "[");
return;
case 132:
case 137: /* RULE */
(void) Dsign4byte();
break;
case 243:
case 244:
case 245:
case 246:
definefont(p);
break;
case 239:
case 240:
case 241:
case 242: /* specials */
mainhandlespecials(k, p);
break;
case 248: /* POST */
ourq = DVIMark() + TotBytesWritten - 1;
inpostamble = true;
return;
}
}
}
static void
readpostamble()
{
int32 k, p, m, indx, FORLIM;
MusFontInfRec *WITH;
VectFontInfRec *WITH1;
LabFontInfRec *WITH2;
if (Dsign4byte() != numerator)
fprintf(logfile, "Postamble numerator doesn't match the preamble!\n");
if (Dsign4byte() != denominator)
fprintf(logfile, "Postamble denominator doesn't match the preamble!\n");
if (Dsign4byte() != mag)
fprintf(logfile, "Postamble magnification doesn't match the preamble!\n");
maxv = Dsign4byte();
maxh = Dsign4byte();
maxs = Dget2byte();
BackupInBuf(2);
cmd2byte(maxs + 2);
/*
* pretend the stack depth does not increase by more than two
*/
totalpages = Dget2byte();
do
{
k = Dget1byte();
if (k >= 243 && k < 247)
{
p = firstpar(k);
Fastdefinefont(p);
k = 138;
}
} while (k == 138); /* NOP */
/*
* here, backup 1, enter all our fonts and then output the 249 that we backed over
*/
BackupInBuf(1);
FORLIM = MFontsDefd;
for (indx = 0; indx < FORLIM; indx++)
{
WITH = MFontTable[indx];
enterfont(WITH->DVIFontNum, WITH->Cksum, WITH->DesSize, WITH->DesSize,
WITH->FontName);
} /* for */
FORLIM = VFontsDefd;
for (indx = 0; indx < FORLIM; indx++)
{
WITH1 = VFontTable[indx];
enterfont(WITH1->DVIFontNum, WITH1->Cksum, WITH1->DesSize, WITH1->DesSize,
WITH1->FontName);
} /* for */
FORLIM = LFontsDefd;
for (indx = 0; indx < FORLIM; indx++)
{
WITH2 = LFontTable[indx];
enterfont(WITH2->DVIFontNum, WITH2->Cksum, WITH2->DesSize, WITH2->DesSize,
WITH2->FontName);
}
cmd1byte(249); /* post post */
if (k != 249)
fprintf(logfile, "byte %d is not postpost!\n", k);
(void) Dsign4byte();
BackupInBuf(4);
cmd4byte(ourq);
m = Dget1byte();
if (m != 2)
fprintf(logfile, "identification should be %d!\n", 2);
m = 223;
while ((m == 223) && (!feof(dvifile)))
m = Dget1byte();
if (feof(dvifile))
return;
fprintf(logfile, "Bad DVI file: signature in should be 223!\n");
jumpout();
}
/* MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN */
int
main(argc, argv)
int argc;
char *argv[];
{
void exit PP((int));
if (setjmp(_JL666))
goto _L666;
initialize();
if (argc < 3)
{
fprintf(stderr, "Usage: textyl dvi-in dvi-out\n");
exit(1);
}
if ((dvifile = fopen(argv[1], "r")) == NULL)
{
perror(argv[1]);
exit(1);
}
if ((outputfil = fopen(argv[2], "w")) == NULL)
{
perror(argv[2]);
exit(1);
}
logfile = stdout;
fprintf(logfile, "%s for Berkeley Unix\n", TylVersion);
p = Dget1byte();
if (p != 247)
{
fprintf(logfile, "Bad DVI file: First byte isn't start of preamble!!\n");
jumpout();
}
p = Dget1byte();
if (p != 2)
fprintf(logfile, "identification in byte 1 should be %d!\n", 2);
numerator = Dsign4byte();
denominator = Dsign4byte();
if (numerator <= 0)
{
fprintf(logfile, "Bad DVI file: numerator is %d!\n", numerator);
jumpout();
}
if (denominator <= 0)
{
fprintf(logfile, "Bad DVI file: denominator is %d!\n", denominator);
jumpout();
}
conv = numerator / 254000.0 * (resolution / denominator);
mag = Dsign4byte();
if (mag <= 0)
{
fprintf(logfile, "Bad DVI file: magnification is % .1E!\n", mag);
jumpout();
}
magfactor = mag / 1000.0;
trueconv = conv;
conv = trueconv * magfactor;
p = Dget1byte(); /* the 'k' of the preamble */
while (p > 0)
{
p--;
(void) Dget1byte();
}
skippages();
if (!inpostamble)
{
while (maxpages-- > 0)
{ /* while */
if (!dopage())
{
printf(" Bad DVI file: page ended unexpectedly!");
fprintf(logfile, "Bad DVI file: page ended unexpectedly!\n");
jumpout();
}
WriteDVIBuf();
ClearDVIBuf();
multifigure = 0;
pgfigurenum = 0;
FTBDs = 0;
didnewfonts = false;
do
{
k = Dget1byte();
if (k >= 243 && k < 247)
{ /* fontdefs */
p = firstpar(k);
definefont(p);
k = 138;
}
} while (k == 138); /* nop */
if (k == 248)
{
inpostamble = true;
ourq = DVIMark() + TotBytesWritten - 1;
break;
}
if (k != 139)
{ /* BOP */
fprintf(logfile, "We did not find BOP when expected\n");
jumpout();
continue;
}
newbackptr = DVIMark() + TotBytesWritten - 1;
currpagenum = Dsign4byte(); /* Count[0] */
for (k = 1; k <= 9; k++) /* WAS count[k] := */
(void) Dsign4byte();
(void) Dsign4byte(); /* backpointer */
BackupInBuf(4);
cmdSigned(oldbackptr, 4);
oldbackptr = newbackptr;
fprintf(logfile, "[");
} /* while */
} /* if not inpostamble */
if (!inpostamble)
skippages();
(void) Dsign4byte(); /* ptr to the last bop in file */
BackupInBuf(4);
cmdSigned(oldbackptr, 4);
readpostamble();
WriteDVIBuf();
while ((TotBytesWritten & 3) != 0) /* final signatures */
OutputByte(223);
fprintf(logfile, "(%d page", currpagenum);
if (currpagenum > 1)
putc('s', logfile);
fprintf(logfile, ", %d bytes).\n", TotBytesWritten);
_L666:
if (ErrorOccurred)
{
fprintf(logfile, "\nSome error(s) occurred.\n");
fprintf(logfile, "Assume that the outputfile is incorrect\n");
}
if (dvifile != NULL)
fclose(dvifile);
if (tfmfile != NULL)
fclose(tfmfile);
if (outputfil != NULL)
fclose(outputfil);
if (logfile != NULL)
fclose(logfile);
exit(0);
return (0);
}